#-*-coding:utf-8-*-
import os
import sys
import shutil
# import nuke
# import nukescripts
from PySide2.QtGui import *
from PySide2.QtCore import *
from PySide2.QtWidgets import *
# if sys.version>'3':
#     from PyQt5.QtGui import *
#     from PyQt5.QtCore import *
#     from PyQt5.QtWidgets import *
# else:
#     from PySide2.QtGui import *
#     from PySide2.QtCore import *f
#     from PySide2.QtWidgets import *
"""
该文件实现的效果是通过后台打包方式，批量对nk工程进行打包存储
运行方式采用的是多线程的方式
PackWindow:主界面窗口类
软件架构说明
一、采用多线程的方式对nk工程进行打包
二、打包规则，确保需要打包的nuke工程正确。所有Read，Write以及相机、lut节点所带的文件都会被打包进来
三、打包后结构
    输出目录：
            /xxx.nk
            /footage
                    /Read1
                    /Read2
                    ...
                    /Write1
                    ...
                    /Camera1
                    ...
                    /lut1
                    ...

"""

class CopyThread(QThread):
    """
    复制文件采用多线程
    """
    def __init__(self,data,OUT_DIR):
        super(CopyThread, self).__init__()
        self.data=data
        self.OUT_DIR=OUT_DIR
        self.all_count=0
        self.count=0
        self.percent=0

    def mz_copy(self,origin_paths, name_list, dir_path):
        """
        这里是打包序列帧
        :param origin_paths: 原文件绝对路径列表
        :param name_list:  原文件名称列表
        :param dir_path: 输出文件目录
        :return:
        """
        # per_count = len(origin_paths)
        # percent = 0
        # footage_path=os.path.join(dir_path,'footage')
        if not os.path.exists(dir_path):
            os.makedirs(dir_path)
        for i in origin_paths:
            des = os.path.join(dir_path, name_list[origin_paths.index(i)])
            shutil.copy(i, des)
            self.count += 1
            self.percent = self.count * 100 / self.all_count

    def show_sequence(self,dir_path, base_name):
        """
        通过输入目录与文件通用名称,需要检测是否为文件，不能因为文件夹名称与文件通过名一样而导致失败
        :param dir_path:
        :param base_name: 文件通用名称
        :return:
        """
        sequence = []
        file_names = []
        file_list = os.listdir(dir_path)
        # print('file_list:',file_list)
        for i in file_list:
            abs_path = os.path.join(dir_path, i)
            if os.path.isfile(abs_path):
                file_names.append(i)
                if base_name in i:
                    sequence.append(abs_path)
        return sequence, file_names

    def check_file(self,path):
        """
        通过nuke读取的路径来获取其对应路径下的所有同名文件序列
        :param path:
        :return:
        """
        file_list = []
        name_list = []

        dir_path, file_name = os.path.split(path)
        if file_name.count('%0') > 0:
            print('是序列')
            base_name = file_name.split('%0')[0]  # 序列文件通用名称
            file_list, name_list = self.show_sequence(dir_path, base_name)
        else:
            if os.path.isfile(path):
                file_list = [path]
                name_list = [os.path.split(path)[1]]
                print('不是序列')
        return file_list, name_list

    def run(self):
        project_name=self.data['project']
        data=self.data['data']
        self.all_count=0

        for k, v in data.items():
            file_paths, name_list = self.check_file(v[1])
            self.all_count+=len(file_paths)

        for k2,v2 in data.items():
            dir_path = os.path.join(self.OUT_DIR,project_name,'footage',v2[0], k2)
            # print(dir_path)
            file_paths, name_list = self.check_file(v2[1])
            self.mz_copy(file_paths, name_list, dir_path)
        # if self.all_count:
        #     self.percent=self.count*100/self.all_count


class MZProgresBar(QWidget):
    """
    打包进度条
    """
    def __init__(self,nk_name):
        super(MZProgresBar, self).__init__()
        self.path=nk_name
        self.main_layout=QVBoxLayout()
        self.main_layout.setSpacing(0)
        label_font=QFont('',12)
        self.show_label=QLabel(nk_name)
        self.show_label.setFont(label_font)
        self.show_label.setStyleSheet('color: #d9d9d9')
        self.progress_layout=QHBoxLayout()
        self.progress=QProgressBar()
        self.progress.setMaximumHeight(10)
        self.percen_label=QLabel('0')
        self.percen_label.setStyleSheet('color: #d9d9d9')
        self.percen_label.setFont(label_font)
        self.progress_layout.addWidget(self.progress)
        self.progress_layout.addWidget(self.percen_label)
        self.main_layout.addWidget(self.show_label)
        self.main_layout.addLayout(self.progress_layout)
        self.setLayout(self.main_layout)

    def set_percent(self,percent):
        self.progress.setValue(percent)
        self.percen_label.setText(str(percent))


class ProgressList(QListWidget):
    """
    进度列表
    """
    def __init__(self,height):
        super(ProgressList, self).__init__()
        self.height=height
        self.setStyleSheet('QListWidget{background-color:#474747}')
        self.nuke_list=[]

    def add_nk(self,nk_name):
        if nk_name not in self.nuke_list:
            self.nuke_list.append(nk_name)
            item=QListWidgetItem()
            item.setSizeHint(QSize(100,self.height))
            mz_p = MZProgresBar(nk_name)
            self.addItem(item)
            self.setItemWidget(item,mz_p)

    def delete_nk(self,nk_name_list):
        """
        删除给定路径的item,删除可以批量操作
        :param nk_name_list:
        :return:
        """
        for i in range(self.count()):
            item=self.item(i)
            w=self.itemWidget(item)
            w_path=w.path
            if w_path in nk_name_list:
                self.takeItem(i)
                self.nuke_list.remove(w_path)

    def set_percent(self,i,percent):
        """
        根据item索引，来设置该item里的进度条值
        :param i:
        :param percent:
        :return:
        """
        item=self.item(i)
        progress_bar=self.itemWidget(item)
        progress_bar.set_percent(percent)


    def test(self,nk):
        item=QListWidgetItem()
        item.setText(nk)
        self.addItem(item)

class NKList(QListWidget):
    """
    nuke工程文件列表
    """
    path_Signal=Signal(list)
    delete_Signal=Signal(list)
    def __init__(self,height):
        super(NKList, self).__init__()
        self.height=height
        self.setStyleSheet('QListWidget{background-color:#474747}')
        self.nk_list=[]
        self.setAcceptDrops(True)
        self.setContextMenuPolicy(Qt.CustomContextMenu)  # 开启自定义右击菜单
        # self.customContextMenuRequested[QPoint].connect(self.right_menu)
        self.customContextMenuRequested.connect(self.right_menu)

    def right_menu(self):
        rMenu = QMenu()
        deleteAction = QAction(u'删除', self)
        deleteAction.triggered.connect(self._delete_items)
        rMenu.addAction(deleteAction)

        testAction = QAction('测试', self)
        testAction.triggered.connect(self.test)
        rMenu.addAction(testAction)
        rMenu.exec_(QCursor.pos())

    def _delete_items(self):
        delete_path=[]
        items=self.selectedItems()
        if items:
            for i in items:
                path=i.text()
                self.takeItem(self.indexFromItem(i).row())
                delete_path.append(path)
                self.nk_list.remove(path)

        self.delete_Signal.emit(delete_path)

    def add_nk(self,nk_name):
        if nk_name not in self.nk:
            self.nuke_list.append(nk_name)
            item=QListWidgetItem()
            item.setSizeHint(QSize(100,self.height))
            mz_p = MZProgresBar(nk_name)
            self.addItem(item)
            self.setItemWidget(item,mz_p)

    def create_nk_item(self,path):
        """
        通过传入的路径获取nk文件
        :param path:
        :return:
        """
        if os.path.isdir(path):  #当是文件夹时
            file_list=os.listdir(path)
            for i in file_list:
                if i.endswith('.nk'):
                    nk_path=os.path.join(path,i).replace('\\','/')
                    if nk_path not in self.nk_list:
                        self.nk_list.append(nk_path)
                        item=QListWidgetItem()
                        item.setText(nk_path)
                        # item.setTextAlignment(Qt.AlignCenter)
                        item.setSizeHint(QSize(100,self.height))
                        item.setForeground(QBrush(QColor('#d9d9d9')))
                        self.addItem(item)

        else:
            if path.endswith('.nk'):
                if path not in self.nk_list:
                    self.nk_list.append(path)
                    item = QListWidgetItem()
                    item.setText(path)
                    # item.setTextAlignment(Qt.AlignCenter)
                    item.setSizeHint(QSize(100, 85))
                    item.setForeground(QBrush(QColor('#d9d9d9')))
                    self.addItem(item)
        self.path_Signal.emit(self.nk_list)
        print('当前nuke工程列表:',self.nk_list)

    def dragEnterEvent(self, evn):
        path_list=[]
        if evn:
            # print(evn.mimeData())
            f_path= evn.mimeData().text()
            c_path=f_path.split('\n')
            # print("c_path:",c_path)
            # print('f_path:',f_path)
            for i in c_path:
                if i:
                    path=i.split(':///')[1]
                    self.create_nk_item(path)

            # print('path:',path)
    # 鼠标放开执行
    # def dropEvent(self, evn):

    # 鼠标移入移出
    # def dragMoveEvent(self, evn):


    def test(self):
        # item=QListWidgetItem()
        # item.setText('aaa.nk')
        # self.addItem(item)
        print('self.nk_list:',self.nk_list)


class PackWindow(QDialog):
    """
    打包主界面窗口。
    #### 使用说明
    一、 设置栏：
            1.列表高度 : 列表栏中列表的高度
            2.nuke exe绝对路径:点击该按钮选择到当前版本nuke的exe程序
            3.输出目录:点击该按钮打包输出到指定目录
            4.输出:执行输出
    二、进度栏：
        显示打包进度
    三、nuke文件：
        可以拖入nk文件或者带nk文化的文件夹，会自动识别里面的nk文件，并以列表形式展现

    """
    def __init__(self):
        super(PackWindow, self).__init__()
        #全局变量
        self.DIR_PATH=os.path.dirname(__file__)
        self.IMG_PATH=os.path.join(self.DIR_PATH,'imgs')
        self.NSCRIPT=os.path.join(self.DIR_PATH,'nscript')  #nuke脚本存放地,对nuke进行操作
        self.CONF_PATH=os.path.join(self.DIR_PATH,'conf')
        self.read_py=os.path.join(self.NSCRIPT,'read_info.py')
        self.out_path=''  #打包输出路径
        self.height=35  #默认item高度
        self.nuke_path='' #默认nuke exe路径
        self.all_nuke_project=[] #当前所有的nuke工程路径集合  反应的是整个nuke多少
        self.thread_list=[]  #当前所有的线程列表
        self.count_list=[]   #所有工程的需要复制的总文件数

        self.icon=QIcon()
        icon_path=os.path.join(self.IMG_PATH,'pack.png')
        self.icon.addPixmap(QPixmap(icon_path))
        self.setWindowIcon(self.icon)
        self.palette=QPalette()
        self.palette.setColor(self.backgroundRole(),QColor('#474747'))
        self.setPalette(self.palette)
        self.title_font=QFont('',15,65)

        self.btn_style = ''' QPushButton{color:black}
                                        QPushButton:hover{color:red}
                                        QPushButton{background-color:#FFDEAD}
                                        QPushButton{border:2px}
                                        QPushButton{border-radius:3px}
                                        QPushButton{padding:1px 1px} '''
        self.ex_btn_style=''' QPushButton{color:black}
                                        QPushButton:hover{color:red}
                                        QPushButton{background-color:#FFDEAD}
                                        QPushButton{border:2px}
                                        QPushButton{border-radius:3px}
                                        QPushButton{padding:1px 1px} '''
        self.setWindowTitle('nuke智能打包工具')
        self.main_layout=QHBoxLayout()
        self.hSplitter=QSplitter(Qt.Horizontal)
        self.left_setting_frame=QFrame()
        self.left_setting_layout=QVBoxLayout()
        self.left_setting_layout.setAlignment(Qt.AlignTop)
        self.left_setting_layout.setSpacing(20)
        self.setting_label=QLabel('设置')
        self.setting_label.setAlignment(Qt.AlignCenter)
        self.setting_label.setFont(self.title_font)
        self.setting_label.setStyleSheet('color: #d9d9d9')

        self.setting_frame=QFrame()
        self.setting_frame_layout=QVBoxLayout()
        self.setting_frame_layout.setContentsMargins(10,25,10,15)
        # self.setting_frame_layout.setSpacing(20)
        self.item_layout=QHBoxLayout()
        self.item_label=QLabel('列表高度:')
        self.item_label.setStyleSheet('color: #d9d9d9')
        self.item_height_edit=QLineEdit()
        # self.item_height_edit.textChanged.connect(self.config_change)
        self.item_height_edit.setMaximumWidth(50)
        self.item_height_edit.setText('35')
        rex = QRegExp("[0-9\.]+$")
        rv = QRegExpValidator(rex, self)
        self.item_height_edit.setValidator(rv)
        self.item_height_edit.setStyleSheet('color: #d9d9d9')

        edit_palette=QPalette()
        edit_palette.setColor(edit_palette.Base,QColor('#474747'))
        self.item_height_edit.setPalette(edit_palette)
        self.item_layout.addWidget(self.item_label)
        self.item_layout.addWidget(self.item_height_edit)
        self.nuke_path_layout=QVBoxLayout()
        self.nuke_path_layout.setContentsMargins(10, 25, 10, 15)
        self.nuke_exe_btn=QPushButton('nuke exe绝对路径:')
        self.nuke_exe_btn.clicked.connect(self._choose_nuke)
        self.nuke_exe_btn.setStyleSheet(self.btn_style)
        self.nuke_exe_edit=QLineEdit()
        self.nuke_exe_edit.setText('C:/Program Files/Nuke11.0v1/Nuke11.0.exe')
        self.nuke_exe_edit.textChanged.connect(self.config_change)
        self.nuke_exe_edit.setStyleSheet('color: #d9d9d9')

        edit_palette=QPalette()
        edit_palette.setColor(edit_palette.Base,QColor('#474747'))
        self.nuke_exe_edit.setAutoFillBackground(True)
        self.nuke_exe_edit.setPalette(edit_palette)
        # self.nuke_exe_edit.setWindowFlags(Qt.FramelessWindowHint)
        self.nuke_path_layout.addWidget(self.nuke_exe_btn)
        self.nuke_path_layout.addWidget(self.nuke_exe_edit)
        self.export_layout=QVBoxLayout()
        self.export_layout.setContentsMargins(10, 25, 10, 15)
        self.export_dir_btn=QPushButton('输出目录:')
        self.export_dir_btn.clicked.connect(self._export_path)
        self.export_dir_btn.setStyleSheet(self.btn_style)
        self.export_edit=QLineEdit()
        self.export_edit.setStyleSheet('color: #d9d9d9')
        self.export_edit.setPalette(edit_palette)
        self.export_layout.addWidget(self.export_dir_btn)
        self.export_layout.addWidget(self.export_edit)
        self.btn_layout=QVBoxLayout()
        self.export_btn=QPushButton('输出')
        self.export_btn.clicked.connect(self._export)
        self.export_btn.setMinimumHeight(50)
        self.export_btn.setStyleSheet(self.ex_btn_style)
        self.btn_layout.addWidget(self.export_btn)
        self.setting_frame_layout.addLayout(self.item_layout)
        self.setting_frame_layout.addLayout(self.nuke_path_layout)
        self.setting_frame_layout.addLayout(self.export_layout)
        self.setting_frame_layout.addLayout(self.btn_layout)

        self.left_setting_layout.addWidget(self.setting_label)
        self.left_setting_layout.addLayout(self.setting_frame_layout)
        self.left_setting_frame.setLayout(self.left_setting_layout)


        self.middle_frame=QFrame()
        self.middle_layout=QVBoxLayout()
        self.progress_label=QLabel('进度')
        self.progress_label.setStyleSheet('color: #d9d9d9')
        self.progress_label.setAlignment(Qt.AlignCenter)
        self.progress_label.setFont(self.title_font)
        self.progress_list=ProgressList(self.height)
        self.middle_layout.addWidget(self.progress_label)
        self.middle_layout.addWidget(self.progress_list)
        self.middle_frame.setLayout(self.middle_layout)


        self.right_frame=QFrame()
        self.right_layout=QVBoxLayout()
        self.right_label=QLabel('nuke文件')
        self.right_label.setStyleSheet('color: #d9d9d9')
        self.right_label.setAlignment(Qt.AlignCenter)
        self.right_label.setFont(self.title_font)
        self.riglt_list=NKList(self.height)
        self.riglt_list.path_Signal.connect(self._add_progress)
        self.riglt_list.delete_Signal.connect(self._delete_progress)
        self.right_layout.addWidget(self.right_label)
        self.right_layout.addWidget(self.riglt_list)
        self.right_frame.setLayout(self.right_layout)

        self.hSplitter.addWidget(self.left_setting_frame)
        self.hSplitter.addWidget(self.middle_frame)
        self.hSplitter.addWidget(self.right_frame)

        self.main_layout.addWidget(self.hSplitter)
        self.setLayout(self.main_layout)

        self.init_config()
        self.timer=QBasicTimer()



    def timerEvent(self, event):
        for thread in self.thread_list:
            percent=thread.percent
            self.progress_list.set_percent(self.thread_list.index(thread),percent)


    def init_config(self):
        config = os.path.join(self.CONF_PATH, 'config')
        data={}
        if os.path.exists(config):
            with open(config,'r',encoding='utf8') as r:
                data=eval(r.read())
            self.height=float(data['height'])
            self.nuke_path=data['nuke_path']
            self.item_height_edit.setText(data['height'])
            self.nuke_exe_edit.setText(self.nuke_path)

    def config_change(self,text):
        print('height_change:',text)
        self.height=self.item_height_edit.text()
        self.nuke_path=self.nuke_exe_edit.text()
        data={}
        data['height']=self.height
        data['nuke_path']=self.nuke_path
        config=os.path.join(self.CONF_PATH,'config')
        with open(config,'w',encoding='utf8') as w:
            w.write(str(data))


    def _choose_nuke(self):
        """
        选择nuke exe地址
        :return:
        """
        openfile_name = QFileDialog.getOpenFileName(self,'选择nuke','','Nuke files(*.exe)')[0]
        self.nuke_exe_edit.setText(openfile_name)

    def _export_path(self):
        """
        打包路径
        :return:
        """
        dir = QFileDialog.getExistingDirectory(self, '选择文件夹')
        self.export_edit.setText(dir)


    def _add_progress(self,path_list):
        """
        槽函数,从拖入的nk文件中传出
        :param path_list:
        :return:
        """
        if path_list:
            self.all_nuke_project=path_list
            for i in path_list:
                self.progress_list.add_nk(i)


    def _delete_progress(self,delete_paths):
        """
        删除的nk文件路径，同时清空掉progress列表
        :param delete_paths:
        :return:
        """
        if delete_paths:
            try:
                for i in delete_paths:
                    self.progress_list.delete_nk(i)
            except Exception as _delete_progress_ERR:
                print(str(_delete_progress_ERR))

    def cmd_back(self,nk_path):
        """
        通过cmd命令读取nk_path,获取所需要的信息
        :param nk_path:
        :return:
        """
        nuke_path = self.nuke_exe_edit.text()
        read_script_path = self.read_py
        nk_project_path = nk_path
        OUT_DIR=self.export_edit.text()
        cmd = f'"{nuke_path}" -t {read_script_path} {nk_project_path} {OUT_DIR}'

        result = os.popen(cmd)
        text = result.read()
        result.close()

        data = text.split("('data:',")[1][:-2]
        # print('data:::', data)
        dic_data = eval(data)
        # print(dic_data)
        # print(type(dic_data))
        return dic_data

    def check_data(self):
        """
        检测整个数据完整性
        :return:
        """
        if self.nuke_exe_edit.text() and self.export_edit.text():
            return True
        else:
            return False


    def _export(self):
        """
        输出
        :return:
        """
        # nk_path=r'E:\PycharmOut\NukeOut\For_Nuke\TEST\tnk.nk'
        # dic_data=self.cmd_back(nk_path)
        # print(dic_data)
        data_list=[]
        if self.check_data():
            if self.all_nuke_project:
                for i in self.all_nuke_project:
                    dic_data=self.cmd_back(i)
                    data_list.append(dic_data)
                    # print(dic_data)
        else:
            print('信息不完整')
            QMessageBox.information(self,'提示','请填入完整信息')
        print('data_list:',data_list)


        if data_list:
            self.timer.start(10,self)
            for data in data_list:
                thread=CopyThread(data,self.export_edit.text())
                self.thread_list.append(thread)
                thread.start()



    def closeEvent(self, arg__1):
        self.height=self.item_height_edit.text()
        self.nuke_path=self.nuke_exe_edit.text()
        data={}
        data['height']=self.height
        data['nuke_path']=self.nuke_path
        config=os.path.join(self.CONF_PATH,'config')
        with open(config,'w',encoding='utf8') as w:
            w.write(str(data))


if __name__ == '__main__':
    app=QApplication(sys.argv)
    p=PackWindow()
    # p=MZProgresBar('aaa')
    p.show()
    sys.exit(app.exec_())






